# -*- coding: utf-8 -*-
"""
Author: Sjy
Description: 维修方案优化模块

单词映射
{
    "全局网格尺寸 Global mesh size": 1.0,
    "损伤数量 Number of damage": 1,
    "损伤类型 Type of damage": "Semi-penetrating Damage",
    "损伤中心位置x Location of damage center x": 3045.0,
    "损伤中心位置y Location of damage center y": -215.0,
        "损伤中心位置z Location of damage center z": 0.0,
    "蜂窝芯子高度 Height of honeycomb core": 15.0,
    "损伤挖除直径 Diameter of damage excavation": 30.0,
    "子模型尺寸长度 Submodel length": 340.0,
    "子模型尺寸宽度 Submodel width": 340.0,
    "搭接宽度 Overlap width": 12.7,
    "胶层厚度 Thickness of adhesive layer": 0.1,
    "预设模型路径 Simulation Model Path": "F:/LXW/NHWXJD/SSFXWXFAYHSJ/WX-2/WXYH-RJCP/1201.cae",
    "上铺层层数 Number of layers in upper skin": 2,
    "上铺层修补层层数 Number of layers of upper skin patching": 4,
    "下铺层层数 Number of layers in lower skin": 2,
        "材料库 Materials library": [
        {
            "材料名称/牌号 Name of material": "Z19-776",
            "材料类型(层合板) Type of material": "Laminate",
            ...
        },
        {
            "材料名称/牌号 Name of material": "HRH 10-3/16-4",
            "材料类型(蜂窝) Type of material": "Honeycomb",
            ...

        }
    ],
    "上铺层 Upper skin": [
        {
            "厚度 Thickness": 0.21,
            "材料名称/牌号 Name of material": "Z19-776",
            "铺层角度 Layer angle": 45.0
        }
    ],
    "下铺层 Lower skin": [
        {
            "厚度 Thickness": 0.21,
            "材料名称/牌号 Name of material": "Z19-776",
            "铺层角度 Layer angle": 45.0
        }
    ],
    "上铺层修补层 Upper skin patching": [
        {
            "铺层序号/名称 No. of pavement": "s1",
            "厚度 Thickness": 0.21,
            "材料名称/牌号 Name of material": "Z19-776",
            "铺层角度 Layer angle": 45.0
        }
    ],
    "蜂窝芯子材料 Honeycomb core material": {
        "材料名称/牌号 Name of material": "HRH 10-3/16-4"
    },
    "下铺层填充层 Fill layer in the lower skin": [
        {
            "材料名称/牌号 Name of material": "Z19-776",
            "铺层角度 Layer angle": 45.0
        }
    ],
    "载荷工况 Load": "load",
    "载荷幅值 Amplitude of load": 1.0,
    "优化功能 Optimization function": "几何参数优化",
    "优化算法 Optimization algorithm": "贝叶斯优化方法",
    "约束条件 Constraint": ["Weight", "Displacement"],
    "搭接宽度(优化) Overlap width optim": [12.7, 15, 25.4],
    "上铺层修补层 Upper skin patching optim": [0, 45, -45, 90],
    "下铺层修补层 Lower skin patching optim": [0, 45, -45, 90],
    "替换蜂窝芯子 Replacement core": [
        "HRH 10-3/16-4",
        "HRH 10-3/16-8"
        ]
}

"""
import os
import copy

from .base import BaseModule
from typing import Dict, Any
import gui.controls.envs as envs
from ..pops import Pops
from ..project import project_manager
from ..params_model import (
    DlgOptimization,
    DlgParamsModeling,
    DlgMaterialSetting,
    DlgMeshPartition,
    DlgLoadBoundary,
    DlgPostProcessing,
)
from ..actions import Actions
import json
from ..uis.dlg_show_optimization_result import DlgShowOptimizationResult
from ..uis.dlg_show_optimization_curve import DlgShowOptimizationCurve


OUTPUT_CONFIG_KEY = "_OUTPUT_CONFIG"


class RepairSchemeModule(BaseModule):
    """维修方案优化模块"""

    def __init__(self):
        super().__init__()

    def init_category(self, ribbon: envs.Ribbonbar) -> Any:
        """初始化工具栏项
        Args:
            ribbon: 工具栏
        Returns:
            Any: 工具栏项
        """
        categoryRepairSchemeOptimization = ribbon.add_category("维修方案优化模块")
        pannelRepairSchemeOptimization = ribbon.add_panel(
            "工作流", categoryRepairSchemeOptimization, titleHide=True
        )
        pannelRepairSchemeOutput = ribbon.add_panel(
            "输出", categoryRepairSchemeOptimization, titleHide=True
        )

        """参数化建模 材料属性设置 网格划分 载荷与边界条件 优化方法 后处理"""
        ribbon.add_large_btn(
            pannelRepairSchemeOptimization,
            {
                "title": "参数化建模",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.show_params_modeling(),
            },
        )

        ribbon.add_large_btn(
            pannelRepairSchemeOptimization,
            {
                "title": "材料属性设置",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.show_material_setting(),
            },
        )

        ribbon.add_large_btn(
            pannelRepairSchemeOptimization,
            {
                "title": "网格划分",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.show_mesh_partition(),
            },
        )

        ribbon.add_large_btn(
            pannelRepairSchemeOptimization,
            {
                "title": "载荷与边界条件",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.show_load_boundary(),
            },
        )

        ribbon.add_large_btn(
            pannelRepairSchemeOptimization,
            {
                "title": "优化方法",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.show_optimization_method(),
            },
        )

        ribbon.add_large_btn(
            pannelRepairSchemeOptimization,
            {
                "title": "后处理",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.show_post_processing(),
            },
        )

        # 输出
        ribbon.add_large_btn(
            pannelRepairSchemeOutput,
            {
                "title": "设置输出路径",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.assign_output_path(),
            },
        )
        ribbon.add_large_btn(
            pannelRepairSchemeOutput,
            {
                "title": "生成数据文件",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.generate_data_file(),
            },
        )
        ribbon.add_large_btn(
            pannelRepairSchemeOutput,
            {
                "title": "设置程序",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.assign_run_file(),
            },
        )
        ribbon.add_large_btn(
            pannelRepairSchemeOutput,
            {
                "title": "运行程序",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.run_cmd(),
            },
        )
        ribbon.add_large_btn(
            pannelRepairSchemeOutput,
            {
                "title": "查看结果模型",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.show_run_result(),
            },
        )

        ribbon.add_large_btn(
            pannelRepairSchemeOutput,
            {
                "title": "查看优化结果",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.show_optimization_result(),
            },
        )
        ribbon.add_large_btn(
            pannelRepairSchemeOutput,
            {
                "title": "查看迭代曲线及最优解",
                "style": "large",
                "styleSheet": "margin-right:10px; padding: 10px 20px;",
                "action": lambda *args: self.show_optimization_curve(),
            },
        )

        return categoryRepairSchemeOptimization

    def init_dock(self, tree) -> None:
        data = [
            {
                "title": "维修方案优化模块",
                "children": [
                    {
                        "title": "参数化建模",
                        "events": {
                            "dbClick": lambda params: self.show_params_modeling()
                        },
                    },
                    {
                        "title": "材料属性设置",
                        "events": {
                            "dbClick": lambda params: self.show_material_setting()
                        },
                    },
                    {
                        "title": "网格划分",
                        "events": {
                            "dbClick": lambda params: self.show_mesh_partition()
                        },
                    },
                    {
                        "title": "载荷与边界条件",
                        "events": {"dbClick": lambda params: self.show_load_boundary()},
                    },
                    {
                        "title": "优化方法",
                        "events": {
                            "dbClick": lambda params: self.show_optimization_method()
                        },
                    },
                    {
                        "title": "后处理",  # 暂不处理
                        "events": {
                            "dbClick": lambda params: self.show_post_processing()
                        },
                    },
                ],
            }
        ]
        tree._set_data(data)

    def show_params_modeling(self):
        """显示参数化建模"""
        py3d = envs.GL.get_value("py3d")
        dlg = DlgParamsModeling.show(py3d)

        db = project_manager.get_repair_scheme_data() or {}
        dbPramsModeling = db.get("paramsModeling") or {}
        if dlg:
            dlg.init(dbPramsModeling)
            # dlg.resize(1000, 1000)
            dlg.paramsModeling_save_signal.connect(
                lambda data: self.paramsModeling_save_signal(data)
            )

        cfgIndex = {}
        with open("config/sys/index.json", "r", encoding="utf-8") as file:
            cfgIndex = json.load(file) or {}
        theme = cfgIndex.get("theme", "dark")  # dark or light
        qss = "styles/dlg.qss"
        if theme == "light":
            qss = "styles/dlg_light.qss"

        dlg.setStyleSheet(open(qss, "r").read())

    def paramsModeling_save_signal(self, data: dict = {}):
        """保存参数化建模  TODO:待完成"""
        # print("paramsModeling_save_signal", data)

        damageType = data.get("损伤类型")  # 损伤类型
        if not damageType:
            print("损伤类型为空")
            return

        if damageType == "贯穿式损伤":
            delKeys = [
                "下铺层修补层",  # 下铺层修补层
                "下铺层填充层",  # 下铺层填充层
            ]
        else:
            delKeys = []
        delKeys = []
        if data.get("损伤类型") != "贯穿式损伤":
            delKeys = [
                "额外挖除尺寸",
                "下铺层修补胶层层数",
                "下铺层修补层层数",
                "下铺层修补层",
                "下铺层填充层",
            ]
        if not (
            data.get("损伤类型") == "蜂窝芯子损伤"
            or data.get("损伤类型") == "贯穿式损伤"
        ):
            delKeys.append("蜂窝芯子修补层")

        db = project_manager.get_repair_scheme_data() or {}
        dbParamsModeling = db.get("paramsModeling", {})

        project_manager.update_repair_scheme_data(
            {
                "paramsModeling": envs.utils.recursion_update_data(
                    dbParamsModeling, data, delKeys=delKeys
                )
            }
        )
        project_manager.save_repair_scheme_data()

    def show_optimization_method(self):
        """显示优化方法  需要额外的参数化建模信息 + 材料数据库信息"""
        db = project_manager.get_repair_scheme_data() or {}

        dbPramsModeling = db.get("paramsModeling") or {}
        dbOptimization = db.get("optimization") or {}
        dbDatabase = project_manager.get_database_data() or {}

        dbMaterials = []
        for key, item in dbDatabase.items():
            for row in item:
                dbMaterials.append(row)

        py3d = envs.GL.get_value("py3d")
        dlg = DlgOptimization.show(py3d)

        if dlg:
            dlg.init(dbOptimization, dbPramsModeling, dbMaterials)
            dlg.optimization_save_signal.connect(
                lambda data: self.optimization_save_signal(data)
            )
        cfgIndex = {}
        with open("config/sys/index.json", "r", encoding="utf-8") as file:
            cfgIndex = json.load(file) or {}
        theme = cfgIndex.get("theme", "dark")  # dark or light
        qss = "styles/dlg.qss"
        if theme == "light":
            qss = "styles/dlg_light.qss"

        dlg.setStyleSheet(open(qss, "r").read())

    def optimization_save_signal(self, data: dict = {}):
        """保存优化方法"""
        project_manager.update_repair_scheme_data({"optimization": data})
        project_manager.save_repair_scheme_data()

    def show_material_setting(self):
        py3d = envs.GL.get_value("py3d")
        dlg = DlgMaterialSetting.show(py3d)

        if dlg:
            db = project_manager.get_repair_scheme_data() or {}
            materialSetting = db.get("materialSetting", {})
            paramsModeling = db.get("paramsModeling", {})
            dataBaseDb = project_manager.get_database_data() or {}
            opt = []
            for key, value in dataBaseDb.items():
                for row in value:
                    opt.append(row)
            dlg.init(materialSetting, paramsModeling, opt)
            dlg.materialSetting_save_signal.connect(
                lambda data: self.materialSetting_save_signal(data)
            )

        cfgIndex = {}
        with open("config/sys/index.json", "r", encoding="utf-8") as file:
            cfgIndex = json.load(file) or {}
        theme = cfgIndex.get("theme", "dark")  # dark or light
        qss = "styles/dlg.qss"
        if theme == "light":
            qss = "styles/dlg_light.qss"

        dlg.setStyleSheet(open(qss, "r").read())

    def materialSetting_save_signal(self, materialSetting: dict = {}):
        """保存材料属性设置  注意现在分开
        {
        '上铺层': # 上铺层
            [{'material': {'E/Enn': '1.0', 'G1/Enn': '2.0', 'G2/Enn': '3.0', '名称': 'jc1'}, 'Angle': 2.0}, {'material': {'E/Enn': '2.0', 'G1/Enn': '3.0', 'G2/Enn': '4.0', '名称': 'jc2'}, 'Angle': 2.0}],
        '下铺层': # 下铺层
            [{'material': {'Es': '4.0', 'Gs': '5.0', '名称': 'FW2', '壁厚t': '1.0', '密度ρ': '3.0', '边长l': '2.0'}, 'Angle': 1.0}, {'material': {'Es': '4.0', 'Gs': '5.0', '名称': 'FW1', '壁厚t': '1.0', '密度ρ': '34.0', '边长l': '2.0'}, 'Angle': 2.0}],
        '上铺层修补层': # 上铺层修补层
            [{'material': {'E1': '1.0', 'E2': '2.0', 'G12': '4.0', 'G13': '5.0', 'G23': '6.0', 'Nu12': '3.0', '名称': 'test1'}, 'Angle': 2.0}, {'material': {'Es': '4.0', 'Gs': '5.0', '名称': 'FW1', '壁厚t': '1.0', '密度ρ': '34.0', '边长l': '2.0'}, 'Angle': 3.0}, {'material': {'E/Enn': '1.0', 'G1/Enn': '2.0', 'G2/Enn': '3.0', '名称': 'jc1'}, 'Angle': 4.0}],
        '下铺层修补层':  # 下铺层修补层
            [{'material': {'E1': '1.0', 'E2': '2.0', 'G12': '4.0', 'G13': '5.0', 'G23': '6.0', 'Nu12': '3.0', '名称': 'test1'}, 'Angle': 3.0}, {'material': {'Es': '4.0', 'Gs': '5.0', '名称': 'FW1', '壁厚t': '1.0', '密度ρ': '34.0', '边长l': '2.0'}, 'Angle': 4.0}, {'material': {'E/Enn': '1.0', 'G1/Enn': '2.0', 'G2/Enn': '3.0', '名称': 'jc1'}, 'Angle': 5.0}],
        '下铺层填充层': 下铺层 填充层
            [{'material': {'E1': '1.0', 'E2': '2.0', 'G12': '4.0', 'G13': '5.0', 'G23': '6.0', 'Nu12': '3.0', '名称': 'test1'}, 'Angle': 2.0}, {'material': {'E1': '5.0', 'E2': '5.0', 'G12': '2.0', 'G13': '3.0', 'G23': '4.0', 'Nu12': '1.0', '名称': 'test3'}, 'Angle': 3.0}],
        '蜂窝芯子材料': # 蜂窝芯子材料
            {'Es': '4.0', 'Gs': '5.0', '名称': 'FW1', '壁厚t': '1.0', '密度ρ': '34.0', '边长l': '2.0'}
        '蜂窝芯子修补层': # 蜂窝芯子修补层
            {'E/Enn': '1.0', 'G1/Enn': '2.0', 'G2/Enn': '3.0', '名称': 'jc1'}
        }
        Args:
            data: 材料设置数据
        Returns:
            None
        Description:
            1. 先获取参数化建模数据
            2. 将材料设置中的数据补全到对应参数化建模数据中的对应位置，2025年5月30日 修改为仅记录材料名称和类型，不记录材料属性，当需要输出的时候将数据输出到对应文件里
        """
        project_manager.update_repair_scheme_data({"materialSetting": materialSetting})
        project_manager.save_repair_scheme_data()

    def _update_materials(self, data, inputData, key):
        savedItems = inputData.get(key, [])
        curItems = data.get(key, [])
        # 上铺层、下铺层、上铺层修补层、下铺层修补层 这些的层数必须是一一对应的关系
        if len(savedItems) == len(curItems):
            for index, item in enumerate(savedItems):
                curItem = curItems[index]
                item.update(curItem.get("材料"))
                item.update({"铺层角度": curItem.get("铺层角度")})
            return savedItems
        else:
            print(f"{key} : 数据不匹配")

    def show_mesh_partition(self):
        """显示网格划分"""
        py3d = envs.GL.get_value("py3d")
        dlg = DlgMeshPartition.show(py3d)

        if dlg:
            db = project_manager.get_repair_scheme_data() or {}
            data = db.get("meshPartition", {})
            dlg.init(data)
            dlg.meshPartition_save_signal.connect(
                lambda data: self.meshPartition_save_signal(data)
            )
        cfgIndex = {}
        with open("config/sys/index.json", "r", encoding="utf-8") as file:
            cfgIndex = json.load(file) or {}
        theme = cfgIndex.get("theme", "dark")  # dark or light
        qss = "styles/dlg.qss"
        if theme == "light":
            qss = "styles/dlg_light.qss"
        dlg.setStyleSheet(open(qss, "r").read())

    def meshPartition_save_signal(self, data: dict = {}):
        """保存网格划分"""
        # print("meshPartition_save_signal", data)
        project_manager.update_repair_scheme_data({"meshPartition": data})
        project_manager.save_repair_scheme_data()

    def show_load_boundary(self):
        """显示载荷与边界条件"""
        py3d = envs.GL.get_value("py3d")
        dlg = DlgLoadBoundary.show(py3d)

        if dlg:
            db = project_manager.get_repair_scheme_data() or {}
            data = db.get("loadBoundary", {})
            dlg.init(data)
            dlg.loadBoundary_save_signal.connect(
                lambda data: self.loadBoundary_save_signal(data)
            )
        cfgIndex = {}
        with open("config/sys/index.json", "r", encoding="utf-8") as file:
            cfgIndex = json.load(file) or {}
        theme = cfgIndex.get("theme", "dark")  # dark or light
        qss = "styles/dlg.qss"
        if theme == "light":
            qss = "styles/dlg_light.qss"
        dlg.setStyleSheet(open(qss, "r").read())

    def loadBoundary_save_signal(self, data: dict = {}):
        """保存载荷与边界条件"""
        # print("loadBoundary_save_signal", data)
        project_manager.update_repair_scheme_data({"loadBoundary": data})
        project_manager.save_repair_scheme_data()

    def show_post_processing(self):
        """显示后处理"""
        py3d = envs.GL.get_value("py3d")
        dlg = DlgPostProcessing.show(py3d)

        if dlg:
            db = project_manager.get_repair_scheme_data() or {}
            data = db.get("postProcessing", {})
            dlg.init(data)
            dlg.postProcessing_save_signal.connect(
                lambda data: self.postProcessing_save_signal(data)
            )
        cfgIndex = {}
        with open("config/sys/index.json", "r", encoding="utf-8") as file:
            cfgIndex = json.load(file) or {}
        theme = cfgIndex.get("theme", "dark")  # dark or light
        qss = "styles/dlg.qss"
        if theme == "light":
            qss = "styles/dlg_light.qss"
        dlg.setStyleSheet(open(qss, "r").read())

    def postProcessing_save_signal(self, data: dict = {}):
        """保存后处理"""
        # print("postProcessing_save_signal", data)
        project_manager.update_repair_scheme_data({"postProcessing": data})
        project_manager.save_repair_scheme_data()

    # 输出
    def assign_output_path(self) -> None:
        """指定输出路径"""

        db = project_manager.get_repair_scheme_data() or {}
        dbOutput = db.get(OUTPUT_CONFIG_KEY, {})
        output_path = dbOutput.get("output_path", "")

        dirInfo = envs.UFile.import_dir(
            dir=output_path, parent=envs.GL.get_value("py3d")
        )
        if not dirInfo or not dirInfo.get("dir"):
            return
        path = dirInfo.get("dir")
        # 检查路径是否存在
        if not os.path.exists(path):
            os.makedirs(path)

        dbOutput["output_path"] = path
        project_manager.update_repair_scheme_data({OUTPUT_CONFIG_KEY: dbOutput})
        project_manager.save_repair_scheme_data()
        envs.MBox.success("已成功设置输出路径")

    def generate_data_file(self) -> None:
        """生成数据文件
        分成两个 1个opt 1个unopt
        2025年6月3日 按刘雄伟 要求生成1个json文件 暂时按提供的json数据生成
        """
        # 获取输出的路径地址
        db = project_manager.get_repair_scheme_data() or {}
        dbOutput = db.get(OUTPUT_CONFIG_KEY, {})
        output_path = dbOutput.get("output_path")
        if not output_path:
            return envs.MBox.warning("请先设置输出参数文件所在的文件夹")
        # 获取数据库数据
        dbDataBase = project_manager.get_database_data() or {}
        # 获取参数化建模数据

        materials = []
        materialNameMaps = {}

        materialMaps = {
            "材料名称": "Name of material",
            "材料类型": "Type of material",
            "密度": "Density",
        }
        for key, value in dbDataBase.items():
            for row in value:
                material = copy.deepcopy(row)
                for key, value in materialMaps.items():
                    if (
                        key in material
                    ):  # 如果key在row中 则将row[key]的值赋值给material[value]
                        material[value] = row.get(key)
                        del material[key]
                materials.append(material)
                materialNameMaps[material.get("Name of material")] = material

        # print("materialNameMaps=", materialNameMaps)
        # print("materials=", materials)

        outputInputData = {
            "Global mesh size": db.get("meshPartition", {}).get("全局网格尺寸", None),
            "Number of damage": db.get("paramsModeling", {}).get("损伤数量", None),
            "Type of damage": db.get("paramsModeling", {}).get("损伤类型", None),
            "Location of damage center x": db.get("paramsModeling", {}).get(
                "损伤中心位置x", None
            ),
            "Location of damage center y": db.get("paramsModeling", {}).get(
                "损伤中心位置y", None
            ),
            "Location of damage center z": db.get("paramsModeling", {}).get(
                "损伤中心位置z", None
            ),
            "Height of honeycomb core": db.get("paramsModeling", {}).get(
                "蜂窝芯子高度", None
            ),
            "Diameter of damage excavation": db.get("paramsModeling", {}).get(
                "损伤挖除直径", None
            ),
            "Submodel length": db.get("paramsModeling", {}).get("子模型尺寸长度", None),
            "Submodel width": db.get("paramsModeling", {}).get("子模型尺寸宽度", None),
            "Overlap width": 12.7,
            "Thickness of adhesive layer": db.get("paramsModeling", {}).get(
                "胶层厚度", None
            ),
            "Simulation Model Path": db.get("paramsModeling", {}).get(
                "预设模型路径", None
            ),
            "Number of layers in upper skin": db.get("paramsModeling", {}).get(
                "上铺层层数", None
            ),
            "Number of layers of upper skin patching": db.get("paramsModeling", {}).get(
                "上铺层修补层层数", None
            ),
            "Number of layers in lower skin": db.get("paramsModeling", {}).get(
                "下铺层层数", None
            ),
            "Materials library": materials,
            # 注意 铺层要合并信息
            "Upper skin": self.merge_skin_data(
                db.get("paramsModeling", {}).get("上铺层", []),
                db.get("materialSetting", {}).get("上铺层", []),
                "上铺层",
                materialNameMaps,
            ),
            "Lower skin": self.merge_skin_data(
                db.get("paramsModeling", {}).get("下铺层", []),
                db.get("materialSetting", {}).get("下铺层", []),
                "下铺层",
                materialNameMaps,
            ),
            # 修补层
            "Upper skin patching": self.merge_skin_data(
                db.get("paramsModeling", {}).get("上铺层修补层", []),
                db.get("materialSetting", {}).get("上铺层修补层", []),
                "上铺层修补层",
                materialNameMaps,
            ),
            "Lower skin patching": self.merge_skin_data(
                db.get("paramsModeling", {}).get("下铺层修补层", []),
                db.get("materialSetting", {}).get("下铺层修补层", []),
                "下铺层修补层",
                materialNameMaps,
            ),
            # 填充层
            "Fill layer in the upper skin": self.merge_skin_data(
                db.get("paramsModeling", {}).get("上铺层填充层", []),
                db.get("materialSetting", {}).get("上铺层填充层", []),
                "上铺层填充层",
                materialNameMaps,
            ),
            "Fill layer in the lower skin": self.merge_skin_data(
                db.get("paramsModeling", {}).get("下铺层填充层", []),
                db.get("materialSetting", {}).get("下铺层填充层", []),
                "下铺层填充层",
                materialNameMaps,
            ),
            # 蜂窝
            "Honeycomb core material": self.merge_skin_data(
                None,
                db.get("materialSetting", {}).get("蜂窝芯子材料", {}),
                "蜂窝芯子材料",
                materialNameMaps,
            ),
            "Honeycomb core plug material": self.merge_skin_data(
                None,
                db.get("materialSetting", {}).get("替换芯子", {}),
                "替换芯子",
                materialNameMaps,
            ),  # 注意这个 替换芯子 是 材料属性设置中的
            # 载荷与边界条件
            "Load": db.get("loadBoundary", {}).get("载荷工况", None),
            "Amplitude of load": db.get("loadBoundary", {}).get("载荷幅值", None),
            # 优化
            "Optimization function": db.get("optimization", {}).get("优化功能", None),
            "Optimization algorithm": db.get("optimization", {}).get("优化算法", None),
            "Optimization objective": db.get("optimization", {}).get("优化目标", None),
            "Constraint": db.get("optimization", {}).get("约束条件", None),
            "Overlap width optim": db.get("optimization", {}).get(
                "搭接宽度(优化)", None
            ),
            "Upper skin patching optim": db.get("optimization", {}).get(
                "上铺层修补层", None
            ),
            "Lower skin patching optim": db.get("optimization", {}).get(
                "下铺层修补层", None
            ),
            "Replacement core": self.merge_material_data(
                db.get("optimization", {}).get("替换蜂窝芯子", []),
                materialNameMaps,
                "替换蜂窝芯子",
            ),
        }

        if not os.path.exists(output_path):
            os.makedirs(output_path)
        file = os.path.join(output_path, "input.json")
        envs.UFile.save_json(file, outputInputData, removeNone=True)
        envs.MBox.success("已成功保存文件！")

    def merge_skin_data(
        self, paramsModelingData, materialSettingData, key, materialNameMaps
    ):
        """合并铺层数据
        Args:
            paramsModelingData: 参数化建模数据
            materialSettingData: 材料设置数据
        Returns:
            None
        Description:
            1. 合并铺层数据
            2. 铺层数据包含材料名称、材料类型、铺层角度、厚度
            3. 因为不能明确哪个 数据是最全的 因此需要将两个数据交叉迭代获取信息
        """

        saveRows = []
        if key in ["上铺层", "下铺层", "上铺层修补层", "下铺层修补层"]:
            if len(paramsModelingData) == 0:
                return []
            for index, item in enumerate(paramsModelingData):
                row = {}
                row["Thickness"] = item.get("厚度")
                if index < len(materialSettingData):
                    materialItem = materialSettingData[index]
                    row["Name of material"] = materialItem.get("材料", {}).get(
                        "材料名称", None
                    )
                    row["Layer angle"] = materialItem.get("铺层角度", None)

                    if key in ["上铺层修补层", "下铺层修补层"]:
                        row["No. of pavement"] = item.get("铺层名称", None)
                saveRows.append(row)
            return self.merge_material_data(saveRows, materialNameMaps, key)
        elif key in ["上铺层填充层", "下铺层填充层"]:
            if len(materialSettingData) == 0:
                return []
            for index, item in enumerate(materialSettingData):
                row = {}
                row["Name of material"] = item.get("材料", {}).get("材料名称", None)
                row["Layer angle"] = item.get("铺层角度", None)
                saveRows.append(row)
            return self.merge_material_data(saveRows, materialNameMaps, key)
        elif key == "蜂窝芯子材料":
            if not materialSettingData:
                return {}
            row = {}
            row["Name of material"] = materialSettingData.get("材料名称", None)
            saveRows.append(row)
            return self.merge_material_data([row], materialNameMaps, key)[0]
        elif key == "替换芯子":
            if not materialSettingData:
                return {}
            row = {}
            row["Name of material"] = materialSettingData.get("材料名称", None)
            return self.merge_material_data([row], materialNameMaps, key)[0]

    def merge_material_data(self, data, materialNameMaps, key):
        """合并材料数据
        Args:
            items: 材料数据
            materialsDB: 材料数据库
        Returns:
            None
        """
        rows = []
        for item in data:
            row = {}
            if key == "替换蜂窝芯子":
                row = materialNameMaps.get(item.get("材料名称"), {})
            else:
                row = item
                material = materialNameMaps.get(item.get("Name of material"), {})
                row.update(material)
            rows.append(row)
        if len(rows) == 0:
            return None
        return rows

    def assign_run_file(self) -> None:
        """指定执行程序文件
        Args:
            None
        Returns:
            None
        """

        fileInfo = envs.UFile.import_custom_type_file(
            "BAT Files (*.bat);; EXE Files (*.exe)",
            file="",
            parent=envs.GL.get_value("py3d"),
        )
        if not fileInfo:
            return
        db = project_manager.get_repair_scheme_data() or {}
        dbOutput = db.get(OUTPUT_CONFIG_KEY, {})
        file = fileInfo.get("file")
        dbOutput["run_file"] = file
        project_manager.update_repair_scheme_data({OUTPUT_CONFIG_KEY: dbOutput})
        project_manager.save_repair_scheme_data()
        envs.MBox.success("保存成功")

    def run_cmd(self) -> None:
        """运行
        Args:
            None
        Returns:
            None
        """

        db = project_manager.get_repair_scheme_data() or {}
        dbOutput = db.get(OUTPUT_CONFIG_KEY, {})
        run_file = dbOutput.get("run_file")
        if not run_file:
            return envs.MBox.warning("请先指定执行程序文件")
        # 检查本地文件是否存在
        if not os.path.exists(run_file):
            return envs.MBox.warning("当前执行程序文件不存在, 请重新指定")
        # envs.run_cmd(data["file"])
        cmd = f"start  {envs.utils.quote_path_with_spaces(run_file)}"
        path = os.path.dirname(run_file)  # 默认的环境目录变更为程序所在目录
        envs.apis.pexecute(cmd, cwd=path, shell=True, isEmit=True)
        envs.MBox.success("已开始执行程序！")

    def show_run_result(self) -> None:
        """显示结果
        Args:
            None
        Returns:
            None
        """
        dictFile = envs.UFile.import_custom_type_file(
            "VTK Files (*.vtk);;VTU Files (*.vtu)"
        )
        if dictFile:
            extension = dictFile.get("extension")
            file = dictFile.get("file")
            if extension == ".vtk":
                return envs.apis.open_vtk(file)
            elif extension == ".vtu":
                return envs.apis.open_vtu(file)

    def show_optimization_result(self) -> None:
        """显示优化结果  优化结果以表格形式显示，包含搭接宽度、替换芯子的材料属性、上铺层修补层角度、极限承载力
        读取csv文件 将对应列的内容读取显示到表格中
        """
        cfgIndex = {}
        with open("config/sys/index.json", "r", encoding="utf-8") as file:
            cfgIndex = json.load(file) or {}
        theme = cfgIndex.get("theme", "dark")  # dark or light
        qss = "styles/dlg.qss"
        if theme == "light":
            qss = "styles/dlg_light.qss"
        dlg = DlgShowOptimizationResult(parent=envs.GL.get_value("py3d"))
        if dlg:
            dlg.init()
            dlg.show()
            dlg.setStyleSheet(open(qss, "r").read())

    def show_optimization_curve(self) -> None:
        """显示优化迭代曲线
        显示优化迭代曲线，方式为读取特定文档的特定列
        """
        cfgIndex = {}
        with open("config/sys/index.json", "r", encoding="utf-8") as file:
            cfgIndex = json.load(file) or {}
        theme = cfgIndex.get("theme", "dark")  # dark or light
        qss = "styles/dlg.qss"
        if theme == "light":
            qss = "styles/dlg_light.qss"
        dlg = DlgShowOptimizationCurve(parent=envs.GL.get_value("py3d"))
        if dlg:
            dlg.init()
            dlg.show()
            dlg.setStyleSheet(open(qss, "r").read())
